package edu.pku.sei.act.actools;

import java.util.List;

import edu.pku.sei.act.actools.util.ACToolsNamingSpace;
import edu.pku.sei.act.actools.util.AbilityOutput;
import edu.pku.sei.act.actools.util.Capability;
import edu.pku.sei.act.actools.util.CapabilityMap;
import edu.pku.sei.act.actools.util.EnvInfo;
import edu.pku.sei.act.actools.util.TaskMessage;

import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class CapabilityManager extends Service {

	private static ICapabilityProvider provider;
	private static ICapabilityProvider systemProvider;
	private static IEnvEntry ee;

	private static ServiceConnection ProviderConnection = new ServiceConnection() {

		public void onServiceConnected(ComponentName arg0, IBinder arg1) {
			provider = ICapabilityProvider.Stub.asInterface(arg1);

		}

		public void onServiceDisconnected(ComponentName arg0) {
			provider = null;
		}

	};

	private static ServiceConnection SystemProviderConnection = new ServiceConnection() {

		public void onServiceConnected(ComponentName arg0, IBinder arg1) {
			systemProvider = ICapabilityProvider.Stub.asInterface(arg1);

		}

		public void onServiceDisconnected(ComponentName arg0) {
			systemProvider = null;
		}

	};

	private static ServiceConnection EEConnection = new ServiceConnection() {

		public void onServiceConnected(ComponentName arg0, IBinder arg1) {
			ee = IEnvEntry.Stub.asInterface(arg1);
		}

		public void onServiceDisconnected(ComponentName arg0) {
			ee = null;
		}

	};

	@Override
	public void onCreate() {
		super.onCreate();

		Intent intent1 = new Intent();
		intent1.setAction(ACToolsNamingSpace.ACToolsComponent.CAPABILITY_PROVIDER);
		bindService(intent1, ProviderConnection, Context.BIND_AUTO_CREATE);
		
		Intent intent2 = new Intent();
		intent2.setAction(ACToolsNamingSpace.ACToolsComponent.SYSTEM_CAPABILITY_PROVIDER);
		bindService(intent2, SystemProviderConnection, Context.BIND_AUTO_CREATE);

		Intent intent3 = new Intent();
		intent3.setAction(ACToolsNamingSpace.ACToolsComponent.ENV_ENTRY);
		bindService(intent3, EEConnection, Context.BIND_AUTO_CREATE);
	}
	
	

	@Override
	public void onDestroy() {
		super.onDestroy();
		unbindService(ProviderConnection);
		unbindService(SystemProviderConnection);
		unbindService(EEConnection);
	}



	private final ICapabilityManager.Stub mbinder = new ICapabilityManager.Stub() {

		public void addCapability(String capability) throws RemoteException {
			ee.LWrite(capability, 0, -1);
		}

		public void removeCapability(String template) throws RemoteException {
			ee.LTake(template);
		}

		public List getMatchedCapability(String template)
				throws RemoteException {
			return ee.LReadMany(template);
		}

		public void match(String capabilityRequired, String capabilityObtained)
				throws RemoteException {
			Capability c1 = new Capability(capabilityRequired);
			Capability c2 = new Capability(capabilityObtained);
			CapabilityMap map = new CapabilityMap(c1, c2);
			ee.LWrite(map.toString(), 0, -1);
		}

		public String invokeCapability(String capabilityRequired, String input)
				throws RemoteException {

			CapabilityMap template = new CapabilityMap(ACToolsNamingSpace.EnvInfo.CAPABILITY_MAP + ",null,"+ capabilityRequired + ",null,null");
			String map_tuple = ee.LRead(EnvInfo.HEAD_TUPLE+","+template.toString());
			if (map_tuple == null) {
				Log.v("@jjj", "matching ability not found!");
				return null;
			}
			Log.v("CM@invokeCapability  map_template",EnvInfo.HEAD_TUPLE+","+template.toString());
			Log.v("CM@invokeCapability matched map",map_tuple);
			CapabilityMap map = new CapabilityMap(map_tuple);
			if (map.getType().equals(Capability.PASSIVE_CAPABILITY)) {
				if (map.getProviderID()
						.equals(ACToolsNamingSpace.ACToolsComponent.SYSTEM_CAPABILITY_PROVIDER)) {
					return systemProvider.invoke(map.getProviderAbility(),
							input);
				} else {
					if (provider == null) {
						Log.v("@jjj", "null capability provider!");
						return null;
					}
					return provider.invoke(map.getProviderAbility(), input);
				}
			} else if (map.getType().equals(Capability.DAEMON_CAPABILITY)) {
				AbilityOutput resultTemplate;
				if (map.getProviderID().equals(ACToolsNamingSpace.ACToolsComponent.SYSTEM_CAPABILITY_PROVIDER)) {
					resultTemplate = new AbilityOutput(systemProvider.invoke(map.getProviderAbility(), input));
				} else {
					if (provider == null) {
						Log.v("@jjj", "null capability provider!");
						return null;
					}
					resultTemplate = new AbilityOutput(provider.invoke(map.getProviderAbility(), input));
				}
				resultTemplate.setReceiverID(map.getTaskID());
				return resultTemplate.toString();
			} else if (map.getType().equals(Capability.ACTIVE_CAPABILITY)) {

			}
			return null;
		}

		public void bindProvider(String providerName) throws RemoteException {
			
			Intent intent1 = new Intent();
			intent1.setAction(ACToolsNamingSpace.ACToolsComponent.CAPABILITY_PROVIDER);
			bindService(intent1, ProviderConnection, Context.BIND_AUTO_CREATE);
		}

		public void abilityCallback(String abilityOutput)
				throws RemoteException {
			AbilityOutput output = new AbilityOutput(abilityOutput);
			CapabilityMap cmap = new CapabilityMap();
			cmap.setProviderID(output.getProviderID());
			cmap.setProviderAbility(output.getAbilityName());
			List<String> ls = ee.LReadMany(EnvInfo.HEAD_TUPLE + "," + cmap);
			for(int i = 0; i<ls.size(); i++) {
				cmap = new CapabilityMap(ls.get(i));
				output.setReceiverID(cmap.getTaskID());
				Log.v("CM@Call back",EnvInfo.HEAD_TUPLE + "," + output);
				ee.notifyLWrite(EnvInfo.HEAD_TUPLE + "," + output, 0, -1);
			}
		}

	};

	@Override
	public IBinder onBind(Intent arg0) {
		return mbinder;
	}

	public static IEnvEntry getEE() {
		return ee;
	}
}
